/*
 * Copyright (C) 2008-2011 University of Deusto
 * 
 * All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.
 * 
 * This software consists of contributions made by many individuals, 
 * listed below:
 *
 * Author: Aitor Gómez Goiri <aitor.gomez@deusto.es>
 */
package otso.se.network.sockets.communication.abstraction;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.restlet.data.Status;
import org.restlet.routing.Template;

import otso.se.network.sockets.communication.abstraction.annotations.HttpHandler;
import otso.se.network.sockets.communication.abstraction.annotations.Path;

public abstract class AbstractSocketApplication implements ISocketApplication {
	
	final protected Set<Class<? extends Object>> resources = new HashSet<Class<? extends Object>>();
	
	public AbstractSocketApplication() {
		//resources.add(e);
	}
	
	protected Class<? extends Object> findBestPattern(String uri) {
		Class<? extends Object> bestPattern = null;
		int bestPatterNumberMatches = -1;
		for(Class<? extends Object> resource: getResources()){
			if (resource.isAnnotationPresent(Path.class)) {
				final String pattern = resource.getAnnotation(Path.class).value();
				final Template tpl = new Template(pattern);
				int matches = tpl.match(uri);
				if(matches > bestPatterNumberMatches){
					bestPattern = resource;
					bestPatterNumberMatches = matches;					
				}
			}
		}
		return bestPattern;
	}
	
	@Override
	public HttpResponse dispatch(HttpRequest request) {
		final Class<? extends Object> resource = findBestPattern(request.getUrl());
		if (resource!=null) {			
			for (Method m : resource.getMethods()) {
		         if (m.isAnnotationPresent(HttpHandler.class)) {
		        	final HttpHandler handler = m.getAnnotation(HttpHandler.class);
		        	if ( handler.value().equals( request.getOperation() ) ) {
						try {
							final Object res = resource.newInstance();
							
							if( res instanceof IConcernedAboutArguments ) {
								// if it has reached this point, resource has Path annotation
								final String pattern = resource.getAnnotation(Path.class).value();
								final Template tpl = new Template(pattern);
								final Map<String, Object> arguments = new HashMap<String, Object>();
								tpl.parse(request.getUrl(), arguments);
								
								((IConcernedAboutArguments)res).setArguments(arguments);
							}
							
							if( res instanceof IConcernedAboutApplication ) {
								((IConcernedAboutApplication)res).setApplication(this);
							}
							
							final Object o = m.invoke(res, request);
							return (HttpResponse) o;
						} catch (IllegalArgumentException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (InvocationTargetException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (SecurityException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (InstantiationException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
		        	}
		        }
			}
		}
		return new HttpResponse(Status.CLIENT_ERROR_NOT_FOUND, System.currentTimeMillis());
	}

	public Set<Class<? extends Object>> getResources() {
		return resources;
	}
}
